#pragma once
#include"usingHeader.hpp"

#define DATABLOCK_SIZE 4069
#define PATH_NAME "."
#define PROJ_ID 0x66
#define gmode 0666

#define USER "user"
#define CREATER "creater"

#define _default_shmid -1


class Shm{
private:
// 用来创建虚拟内存空间
    void Create_Helper(int flag){
        int shmid = shmget(_key, _size, flag);

        string ret;
        if(_user == USER) ret += "user get shm";
        else if(_user == CREATER) ret += "creater create shm"; 

        if(shmid < 0) ERR_EXIT(ret.c_str());
        else cout << _user << " : " << "shm get/create success" << endl;
        _shm_id = shmid;
    }

    void Create(){
        if(_user == CREATER){
            Create_Helper(IPC_CREAT | IPC_EXCL | gmode);
        }
        else if(_user == USER){
            Create_Helper(IPC_CREAT);
        }
    }

// 销毁内存空间
    void Destroy(){
        if(_user == USER) return;
        int rm_id = shmctl(_shm_id, IPC_RMID, nullptr);
        if(rm_id < 0) ERR_EXIT("destroy segment");
        else cout << _user << " : " << "destroy segment success!" << endl;
    }

// 将共享内存空间和当前进程的虚拟内存进行关联
    void Attach(){
        void* start_mem = shmat(_shm_id, nullptr, 0);
        if((long long)start_mem < -1) ERR_EXIT("attach");
        else cout << _user << " : " << "attach success!" << endl;
        _start_mem = start_mem;
        cout << _user << " : " << _start_mem << endl;
    }

    void Detach(){
        int detach_id = shmdt(_start_mem);
        if(detach_id < 0) ERR_EXIT("detach");
        else cout << _user << " : " << "detach succcess!" << endl;
    }

public:
    Shm(const string& pathname, int proj_id, const string& user)
        :_size(DATABLOCK_SIZE), 
        _user(user), 
        _shm_id(_default_shmid), 
        _start_mem(nullptr)
    {
        int key = ftok(pathname.c_str(), proj_id);
        if(key < 0) ERR_EXIT("ftok");
        else cout << _user << " : " << "ftok success!" << endl;
        _key = key;
        cout << _key << endl;

        Create();
        Attach();
    }

    ~Shm(){
        cout << _user << " : " << "going to remove segment" << endl;
        Detach();
        Destroy();
    }

    void* Get_shm_addr() const{
        return _start_mem;
    }

    size_t Size() const{
        return _size;
    }

    struct shmid_ds get_shm_info(){
        struct shmid_ds _info;
        shmctl(_shm_id, IPC_STAT, &_info);
        cout << "引用计数: " <<  _info.shm_nattch << endl;
        cout << "共享内存大小: " <<_info.shm_segsz << endl;
        cout << "权限: " << _info.shm_perm.mode << endl; 
        cout << "key: " << _info.shm_perm.__key << endl;
        return _info;
    }
private:
    key_t _key;
    size_t _size;
    string _user;
    int _shm_id;
    void* _start_mem;
};